/*
 * Copyright (C) 2008 Alessandro Sivieri <alessandro.sivieri@chimera-bellerofonte.eu>.
 *
 *  This file is part of Daex.
 *
 *  Daex is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Foobar is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
 */
package eu.chimera_bellerofonte.tesi.datatypes;

import java.io.Serializable;
import java.util.ArrayList;


/**
 * <p>Questa classe descrive la struttura dati Album,
 * contenente le informazioni generali valide per tutte
 * le tracce ed i riferimenti alle singole tracce; i
 * valori generali sono settati qui e vengono propagati
 * alle canzoni sia in fase di costruzione che di setting
 * posteriore.
 * <br>
 * Contiene un riferimento ad un oggetto di tipo Dvd in
 * quanto da questo ne ricava le informazioni per eseguire
 * un ripping corretto. Implementa Serializable per poter
 * essere eventualmente inviata lungo un qualche tipo di stream.
 * <br>
 * Non e' possibile costruire un oggetto di tipo Album
 * vuoto (ovvero l'implementazione di Dvd scelta deve
 * essere valida e correttamente inizializzata).</p>
 * 
 * @see java.io.Serializable
 * @see eu.chimera_bellerofonte.tesi.datatypes.Dvd
 * @see eu.chimera_bellerofonte.tesi.datatypes.Song
 * @author  Sivieri Alessandro
 * @author  Vitucci Nicola
 * @version  20/apr/07
 */
public class Album implements Serializable, Cloneable
{
	static final long serialVersionUID = 1L;
	/**
	 * Etichetta per un artista ancora indefinito.
	 */
	public static final String GENERICARTIST="Unknown";
	/**
	 * Etichetta per un titolo di album indefinito.
	 */
	public static final String GENERICALBUM="Untitled";
	/**
	 * Etichetta per un titolo di canzone indefinito.
	 */
	public static final String GENERICTITLE="Untitled";
	/**
	 * Etichetta per un genere indefinito.
	 */
	public static final Genre GENERICGENRE=Genre.BLUES;
	/**
	 * Indice per un titolo di dvd indefinito.
	 */
	public static final int GENERICDVDTITLE=0;
	
	private String album=null;
	private String artist=null;
	private Genre genre=null;
	private int dvdTitle=0;
	private ArrayList<Song> songs=null;
	private Dvd dvd=null;
	
	/**
	 * Costruttore vuoto e con visibilita' di package per evitare
	 * che venga utilizzato a sproposito; creato per comodita'
	 * nel caricamento di dati salvati.
	 */
	Album()
	{
		songs=new ArrayList<Song>(0);
	}
	
	private void init() throws DvdException
	{
		if(songs==null)
		{
			this.songs=new ArrayList<Song>(0);
		}
		else
		{
			this.songs.clear();
		}
		for(int i=0; i<dvd.getMainTitleChapters(); i++)
		{
			songs.add(new Song(this.artist, (i+1), this.album, this.genre, i+1, i+1));
		}
	}
	
	/**
	 * Costruttore; riceve come parametro solamente il riferimento
	 * al device fisico ed inserisce valori di default agli altri
	 * campi.
	 * 
	 * @param dvd descrittore dei dettagli del DVD Video
	 * @throws DvdException eccezione lanciata per problemi verso il device fisico
	 */
	public Album(Dvd dvd) throws DvdException
	{
		this.dvd = dvd;
		this.album=GENERICALBUM;
		this.artist=GENERICARTIST;
		this.genre=GENERICGENRE;
		this.dvdTitle=this.dvd.getMainTitle();
		init();
	}

	/**
	 * Costruttore; memorizza correttamente tutte le informazioni che
	 * vengono passate.
	 * 
	 * @param dvd descrittore dei dettagli del DVD Video
	 * @param album titolo dell'album
	 * @param artist artista dell'album
	 * @param genre genere dell'album
	 * @throws DvdException eccezione lanciata per problemi verso il device fisico
	 */
	public Album(Dvd dvd, String album, String artist, Genre genre) throws DvdException
	{
		this.dvd=dvd;
		this.album = album;
		this.artist = artist;
		this.genre = genre;
		this.dvdTitle=this.dvd.getMainTitle();
		init();
	}

	/**
	 * Questo metodo ritorna il valore attuale di album.
	 * @return  il valore attuale di album
	 * @uml.property  name="album"
	 */
	public String getAlbum()
	{
		return album;
	}

	/**
	 * Questo metodo setta album con il valore dato.
	 * @param album  il nuovo valore per questo campo
	 * @uml.property  name="album"
	 */
	public void setAlbum(String album)
	{
		this.album = album;
		for(Song s: songs)
			s.setAlbum(this.album);
	}

	/**
	 * Questo metodo ritorna il valore attuale di artist.
	 * @return  il valore attuale di artist
	 * @uml.property  name="artist"
	 */
	public String getArtist()
	{
		return artist;
	}

	/**
	 * Questo metodo setta artist con il valore dato.
	 * @param artist  il nuovo valore per questo campo
	 * @uml.property  name="artist"
	 */
	public void setArtist(String artist)
	{
		this.artist = artist;
		for(Song s: songs)
			s.setArtist(this.artist);
	}

	/**
	 * Questo metodo ritorna il valore attuale di genre.
	 * @return  il valore attuale di genre
	 * @uml.property  name="genre"
	 */
	public Genre getGenre()
	{
		return genre;
	}

	/**
	 * Questo metodo setta genre con il valore dato.
	 * @param genre  il nuovo valore per questo campo
	 * @uml.property  name="genre"
	 */
	public void setGenre(Genre genre)
	{
		this.genre = genre;
		for(Song s: songs)
			s.setGenre(this.genre);
	}

	/**
	 * Questo metodo ritorna il valore attuale di songs.
	 * @return  il valore attuale di songs
	 * @uml.property  name="songs"
	 */
	public ArrayList<Song> getSongs()
	{
		return songs;
	}

	/**
	 * Questo metodo setta songs con il valore dato.
	 * @param songs  il nuovo valore per questo campo
	 * @uml.property  name="songs"
	 */
	public void setSongs(ArrayList<Song> songs)
	{
		this.songs = songs;
	}
	
	/**
	 * Facility per aggiungere una canzone all'album.
	 * 
	 * @param song la canzone da aggiungere
	 */
	public void addSong(Song song)
	{
		this.songs.add(song);
	}

	/**
	 * Questo metodo ritorna il valore attuale di dvd.
	 * @return  il valore attuale di dvd
	 * @uml.property  name="dvd"
	 */
	public Dvd getDvd()
	{
		return dvd;
	}
	
	/**
	 * Questo metodo setta dvd con il valore dato.
	 * 
	 * @param dvd il nuovo valore per questo campo
	 * @throws DvdException eccezione lanciata a fronte di problemi con il device
	 */
	void setDvd(Dvd dvd) throws DvdException
	{
		this.dvd = dvd;
		this.dvdTitle=this.dvd.getMainTitle();
	}
	
	/**
	 * Questo metodo setta dvd con il valore dato
	 * ed aggiunge ulteriori informazioni sui valori
	 * per il nuovo dvd registrato.
	 * 
	 * @param dvd il nuovo valore per questo campo
	 * @param artist il nuovo artista da settare
	 * @param album il nuovo album da settare
	 * @param genre il nuovo genere da settare
	 * @throws DvdException eccezione lanciata a fronte di problemi con il device
	 */
	public void setDvd(Dvd dvd, String artist, String album, Genre genre) throws DvdException
	{
		this.dvd = dvd;
		this.album=album;
		this.artist=artist;
		this.genre=genre;
		this.dvdTitle=this.dvd.getMainTitle();
		init();
	}

	/**
	 * Questo metodo ritorna il valore attuale di dvdTitle.
	 * @return  il valore attuale di dvdTitle
	 * @uml.property  name="dvdTitle"
	 */
	public int getDvdTitle()
	{
		return dvdTitle;
	}

	/**
	 * Questo metodo setta dvdTitle con il valore dato e carica i
	 * nuovi valori per i campi.
	 * @param dvdTitle  il nuovo valore per questo campo
	 * @throws DvdException eccezione lanciata in caso di problemi
	 */
	public void setDvdTitle(int dvdTitle) throws DvdException
	{
		this.dvdTitle = dvdTitle;
		dvd.setMainTitle(dvdTitle);
		init();
	}
	
	/**
	 * Metodo per ottenere le ricorrenze di una canzone all'interno
	 * dell'album utilizzando il titolo come elemento di ricerca.
	 * 
	 * @param title il titolo della canzone
	 * @return il numero di ricorrenze (>=0)
	 */
	public int getRecurrency(String title)
	{
		int total=0;
		for(Song s: songs)
		{
			if(s.getTitle().equals(title))
			{
				total++;
			}
		}
		return total;
	}

	/**
	 * Metodo per la visualizzazione delle informazioni dell'album.
	 * 
	 * @see java.lang.Object#toString()
	 * @return una stringa che descrive l'oggetto
	 */
	@Override
	public String toString()
	{
		return "Album: "+getAlbum()+"\nArtista: "+getArtist()+"\nGenere: "+getGenre()+"\nNumero di tracce: "+getSongs().size();
	}

	/**
	 * @see java.lang.Object#clone()
	 */
	@Override
	public Object clone() throws CloneNotSupportedException
	{
		Album album=new Album();
		for(Song s: songs)
			album.addSong((Song) s.clone());
		return album;
	}

}
